;gdt
[bits 16]
gdt_start:
gdt_null:			; the mandatory null discriptor
	dd	0x0			; 'dd' means define double word (i.e. 4 bytes)
	dd	0x0
	
gdt_code:			; the code segment descriptor
	; base 0x0, limit 0xfffff
	; 1st flags: (present) 1 (pricilege) 00 (descriptor type) 1 -> 1001b
	; type flags : (code) 1 (confroming) 0 (readable) 1 (accessed) 0 -> 1010b
	; 2nd flags : (granularity) 1 (32-bit default) 1 (64-bit seg) 0 (AVL) 0 ->1100b
	dw	0xffff		; limit (bits 0 - 15)
	dw	0x0			; base (bits 0 - 15)
	db	0x0			; base (bits 16 - 23)
	db	10011010b	; 1st flags, type flags
	db	11001111b	; 2nd flags, limit (bits 16 - 19)
	db	0x0			; base (bits 24 - 31)
	
gdt_data:			; the data segment descriptor
	; same as code segment except for the type flags
	; type flags : (code) 0 (expand down) 0 (writable) 1 (accessed) 0 -> 0010b
	dw	0xffff		; limit (bits 0 - 15)
	dw	0x0			; base (bits 0 - 15)
	db	0x0			; base (bits 16 - 23)
	db	10010010b	; 1st flags, type flags
	db	11001111b	; 2nd flags, limit (bits 16 - 19)
	db	0x0			; base (bits 24 - 31)
	
gdt_end:			; the reason for putting a label at the end of the
					; GDT is so we can have the assembler calculate
					; the size of the GDT for the gdt descriptor (below)
					
; GDT descriptor
gdt_descriptor:
	dw	gdt_end - gdt_start - 1		; size of our GDT, always less one
	dd	gdt_start					; start address of our GDT
	
; deing some handy constants for the GDT segment descriptor offsets, which
; are what segment registers must contain when in protected mode. For example,
; when we set DS = 0x10 in PM, the CPU knows that we mean it to use the
; segment described at offset 0x10 (i.e. 16 bytes) in out GDT, which in our
; case is the DATA segment (0x0 -> NULL; 0x08 -> CODE; 0x10 ->DATA)
CODE_SEG	equ	gdt_code - gdt_start
DATA_SEG	equ	gdt_data - gdt_start